﻿/*
  Copyright (c) 2011, Mikheev Rostislav
  Copyright (c) 2011, FreshFarsh team

  Steel Engine source code is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 2
  of the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
/**
  @author Mikheev Rostislav <hacenator@gmail.com>
  @date 28.12.2010
  @brief Project sourcefile
*/


# define BOOST_DYN_LINK
# define BOOST_PYTHON_USE_LIB

#include "SDL/SDL.h"
#include <boost/python.hpp>
#include "GL/glew.h"
#include "exception.h"
#include "log.h"
#include "io_file.h"
#include "scripts/script.h"
#include "window_manager.h"
#include "map.h"
#include "camera.h"
#include "config.h"

#include "gui/core.h"
#include "gui/font.h"

///< define project namespace
using namespace steel;

WindowManager * window;

GUILayer * gui;

Map * map;
Camera * camera;
Config * config;

// boost python binding
namespace python = boost::python;

/*
 * Binding bacis python structures
 * TODO(hacenator): take out all python binding to single file
 */
BOOST_PYTHON_MODULE(steel) {
  /* log module */
  #ifdef PYTHON_BINDING_LOG
  python::class_<PythonBinding_Log>("log")
    .def("info", &PythonBinding_Log::Info, "Write information message in log file")
    .def("warn", &PythonBinding_Log::Warn, "Write warning message in log file")
    .def("error", &PythonBinding_Log::Error, "Write error message in log file (no terminate application). ");
  #endif

  /* config modile */
  #ifdef PYTHON_BINDING_CONFIG
  python::class_<PythonBinding_Config>("config")
    .def("getFloat", &PythonBinding_Config::GetFloat, "Get float value of configuration parameter with name `key`")
    .def("getInteger", &PythonBinding_Config::GetInteger, "Get decimal value of configuration parameter with name `key`")
    .def("getString", &PythonBinding_Config::GetString, "Get string value of configuration parameter with name `key`")
    .def("getDefaultFloat", &PythonBinding_Config::GetDefaultFloat, "If parameter with name `key` exists return them value as float, otherwise return `defValue`")
    .def("getDefaultInteger", &PythonBinding_Config::GetDefaultInteger, "If parameter with name `key` exists return them value as decimal, otherwise return `defValue`")
    .def("getDefaultString", &PythonBinding_Config::GetDefaultString, "If parameter with name `key` exists return them value as string, otherwise return `defValue`")
    .def("setFloat", &PythonBinding_Config::SetFloat, "Set value of configuration parameter with name `key`")
    .def("setInteger", &PythonBinding_Config::SetInteger, "Set value of configuration parameter with name `key`")
    .def("setString", &PythonBinding_Config::SetString, "Set value of configuration parameter with name `key`")
    .def("clear", &PythonBinding_Config::Clear, "Clear all parameters");
  #endif
}

///---------------------------------------------------------------------------

void keyDownEvent(int key) {
  if (key == SDLK_UP) {
    camera->Translate(0, -0.1);
  }
  else if (key == SDLK_DOWN) {
    camera->Translate(0, +0.1);
  }
  else if (key == SDLK_LEFT) {
    camera->Translate(+0.1, 0);
  }
  else if (key == SDLK_RIGHT) {
    camera->Translate(-0.1, 0);
  }
}

bool myInit() {
  Log::GetInstance()->Info("GLInit\n");

  // Camera
  camera = new Camera();
  camera->Init(window->width(), window->height());

  // Map
  map = new Map(window, camera, gui);
#ifdef DEBUG
  map->set_edit_mode(true);
#endif

  return true;
}

void myDraw() {
  camera->Apply();
  map->Draw();

  camera->Reset();
  gui->font()->Printf(0, 45, L"Camera: %f; %f; %f",
      camera->GetOffsetX(),
      camera->GetOffsetY(),
      camera->GetOffsetZ()
  );
}

void myTerminate() {
  delete map;
  delete camera;
  delete window;
  delete gui;
}

/*
 * Application enter point
 */
int main(int argc, char* argv[]) { // I change _TCHAR to char when linux porting source. Test on win32
  sLog->Infof("Initialize Steel @'%s'\n", argv[0]);

  //
  // Initialize python enhancment
  //
  sLog->Info("Initialize Python enhacments\n");

    //python::import("sys").attr("stderr") = jLog::getInstance();
    //python::import("sys").attr("stdout") = jLog::getInstance();

  Py_Initialize();

  int error = PyImport_AppendInittab("steel", initsteel);
    if (error) {
      sLog->Warnf("Python initialization error. Code %d\n", error);
    }

  // config script
  sLog->Info("Loading config script\n");
  Script * script = new Script();
  script->LoadFromFile("config.py");
  script->Execute();
  delete script;

  //
  // Initialize SDL
  //
  sLog->Infof("Initialize SDL\n");
  if (SDL_Init(SDL_INIT_VIDEO) < 0) {
    sLog->Errorf("Couldn't initialize SDL: %s\n", SDL_GetError());
  }

  //
  // Window
  //
  window = new WindowManager();

  // Events
  window->AddListener((VariantCallback)&myInit, WindowManager::kListenInit);
  window->AddListener((VariantCallback)&myDraw, WindowManager::kListenDraw);
  window->AddListener((VariantCallback)&keyDownEvent, WindowManager::kListenKeyDown);

  int wnd_width = sConfig->GetDefaultInteger(CONFIG_PARAMETER_WINDOWS_WIDTH , CONFIG_DEFAULT_WINDOWS_WIDTH);
  int wnd_height = sConfig->GetDefaultInteger(CONFIG_PARAMETER_WINDOWS_HEIGHT, CONFIG_DEFAULT_WINDOWS_HEIGHT);
  int wnd_fullscreen = sConfig->GetDefaultInteger(CONFIG_PARAMETER_WINDOWS_FULLSCREEN, CONFIG_DEFAULT_WINDOWS_FULLSCREEN);
  int gl_multisample = sConfig->GetDefaultInteger(CONFIG_PARAMETER_OPENGL_MULTISAMPLE, CONFIG_DEFAULT_OPENGL_MULTISAMPLE);

  // Gui
  gui = new GUILayer(window, wnd_width, wnd_height);
  gui->set_info(true);

  window->SetAntialiasingSamples(gl_multisample);
  window->OpenWindow(wnd_width, wnd_height, wnd_fullscreen);

  // App Loop

  #ifdef DEBUG
  sLog->Warn("Execution finished. Press any key to exit.");
  getchar();
  #endif

  return 0;
}
